Using Options
This section describes the rules for option negotiation and how negotiation is affected by the function you use to set options. It also explains how you use endpoint functions to set and retrieve option values and how you use Open Transport utility functions to construct an options buffer and parse through an options buffer.If your application needs to negotiate option values, you must read the sections "Determining Which Function to Use to Negotiate Options," "Negotiating Options," and "Obtaining the Maximum Size of an Options Buffer." After reading these sections, you can read whichever of the remaining sections describes the task you need to accomplish.
Determining Which Function to Use to Negotiate Options
You can negotiate options using theOTOptionManagement
function or using any one of the endpoint functions used to transfer data or establish a connection. The following bulleted list summarizes the major differences between using
theOTOptionManagement
function or using other endpoint functions to set an option value.
- Options specified using the
OTOptionManagement
function affect all functions called by an endpoint. Options specified using individual endpoint functions affect only the connection, transaction, or datagram for which they are set. For example, you can call theOTOptionManagement
function to turn the checksum option on; you could override that value by calling theOTSndUData
function and turning the checksum option off for the duration of that function call. The next time you call theOTSndUData
function, the default value, set with theOTOptionManagement
function would apply, so the checksum option would be off.- The
OTOptionManagement
function is the only way that you can obtain default option values or check for current values of all options supported by an endpoint.- When attempting to set multiple options, if an option is illegal or rejected, the
OTOptionManagement
function still returns successfully, indicating for each option in the buffer whether it has been successfully negotiated. In the same circumstances, any other function returns an error, and even though some of the options might have been successfully negotiated, you have no way of knowing which were and which were not.- If you are using the
OTOptionManagement
function to set or verify option values, all options in the buffer must be for the same protocol. If you use any other function to negotiate options or to check their value, the buffer can contain options set for different protocols.- If association-related options contain information that is transmitted across the network or if they affect the transmission itself, they take effect when Open Transport establishes the connection, sends the transaction, or transmits the datagram. If you use the
OTOptionManagement
function to change such an option, the endpoint provider checks whether the option is supported and negotiates a value according to its current knowledge. Then it writes the negotiated value to the endpoint's internal options buffer. However, more negotiations might take place when the connection is established or the transaction or datagram is sent. This can result in a degradation of the option value or even in a negotiation failure. If the negotiation succeeds, the newly negotiated values are written to the internal options buffer.
Negotiating Options
This section describes the rules governing option negotiation and the error conditions that might occur during this process. Unless stated otherwise, these rules apply to all functions that allow you to specify option values.A basic rule to keep in mind is that options change only as the result of successful negotiations or partly successful negotiations. If you use any function except the
OTOptionManagement
function, the changes last for the duration of that function invocation. Option values are not changed by a change in the state of an endpoint. Once you change an option value permanently, there is no function that you can call to restore an option to its previous value, unless that previous value is the default value.Negotiating Multiple Options
You can use one function to negotiate several options by placing the options
in the options buffer passed to the function. If one of the options is ignored
or rejected for any reason, the outcome depends on the function you use to
set options.
If you specify the same option more than once, the endpoint provider does not check for duplicate occurrences of the same option. It simply processes the options one after another. However, the endpoint provider might negotiate options in any order; therefore, it is not safe to make any assumptions that a later occurrence of an option will override an earlier occurrence.
- If you use the
OTOptionManagement
function, the function returns the result of negotiating each option in thestatus
field of each option. The failure of one or more options does not cause the function to fail.- The
OTConnect
,OTAccept
,OTSndUdata
, orOTSndURequest
functions might succeed or fail, depending on the implementation and on the error condition. Options that are not supported are generally ignored; they do not cause a function to fail or a connection to abort. However, if the endpoint provider is unable to negotiate options that are absolute requirements or options that are read-only, these functions will fail.If option negotiation causes one of these functions to fail, it is possible that some options were successfully negotiated before the failure. However, it is not possible to determine which of the options caused the failure.
Initiating an Option Negotiation
You initiate an option negotiation by calling theOTOptionManagement
function with the flagT_NEGOTIATE
set or by calling theOTConnect
,OTSndUData
, orOTSndURequest
function and specifying an options buffer length that is greater than 0. You can specify values for some or all of the options supported by an endpoint. The endpoint provider takes values for options that you do not specify explicitly in the options buffer, from the endpoint's internal options buffer. This buffer contains the endpoint's current option values; these could be default values, values that you specified when you configured the provider, or values resulting from a previous negotiation.If the endpoint supports an option, the possible outcome of option negotiation depends on whether the option is an absolute requirement, as described in the next two sections. If the endpoint does not support the option, the
OTOptionManagement
function reportsT_NOTSUPPORT
in thestatus
field. TheOTConnect
,OTSndUData
, orOTSndURequest
functions ignore the option.Options That Are Absolute Requirements
If the option is an absolute requirement, the result of the negotiation depends on whether the negotiated value is the same as the requested value. If it is, thestatus
field in theTOption
structure describing the option is set toT_SUCCESS
when the function returns. If the negotiated value is not the same as the requested value, the result depends on the function used to negotiate
the option:
- The
OTOptionManagement
function returns successfully, but the returned option has itsstatus
field set toT_FAILURE
.- A call to the
OTConnect
function fails. If the call is synchronous, the function returns with thekOTLookErr
result. If the call is asynchronous, the endpoint provider issues aT_DISCONNECT
event to let you know that the connection has been rejected.- The
OTSndUData
function fails with thekOTLookErr
result; or if it returns successfully, the endpoint provider issues aT_UDERR
event to indicate that the datagram was not sent.
Options That Are not Absolute Requirements
If the requested option is not an absolute requirement, the result of the negotiation depends on whether the negotiated value is the same as the requested value. If it is, the endpoint provider sets thestatus
field of theTOption
structure describing the option toT_SUCCESS
. If the negotiated value is different than the proposed value, the endpoint provider sets thestatus
field of theTOption
structure describing the options toT_PARTSUCCESS
.Conflicting Option Values
It is possible that a requested option value conflicts with the value of another option that is proposed with the same call to the function or that is currently effective. The endpoint provider might not detect these conflicts immediately, and later they might lead to unpredictable results. If the endpoint provider detects conflicts at negotiation time, the conflicts are resolved according to the rules stated above.An endpoint provider usually detects conflicts at the time it establishes a connection or sends a datagram. Consequently, if you use the
OTOptionManagement
function to set options, you might not become aware
that there is a problem due to conflicting options until the options are
actually exercised during connection establishment or data transmission.Privileged or Read-Only Options
A protocol implementation can define options to be privileged or read only. These two categories are not necessarily separate. A privileged option might be inaccessible or read-only for nonprivileged clients. An option might be read-only for all clients or solely for nonprivileged clients. Here are two general guidelines to keep in mind:
If you request negotiation of a privileged option using the
- A client must be privileged to be able to change a privileged option.
In the Macintosh implementation of Open Transport, there are no
privileged options.- A client cannot usually change the value of a read-only option.
An option might be read-only in some endpoint states but not in others. For example, the ISO quality-of-service options are negotiable in the
T_IDLE
andT_INCON
states, and read-only in all other states exceptT_UNINIT
. Consult the documentation provided for the protocol you are using to determine whether an endpoint's state affects the status of read-only options.
OTOptionManagement
function, the function returns successfully with thestatus
field of the privileged option set toT_NOTSUPPORT
. If you use theOTConnect
,OTAccept
,OTSndUData
, orOTSndURequest
functions, the option is ignored--that is, the function result is not affected by the fact that the options are not supported.If you request negotiation of a read-only option using the
OTOptionManagement
function, the function returns with thestatus
field of the read-only option set toT_READONLY
. If you use any other function to change a read-only option, the results vary with the function used:
- The
OTAccept
orOTConnect
functions fail with thekOTAccessErr
result, or the connection establishment aborts and the endpoint provider issues aT_DISCONNECT
event. If the connection aborts, a synchronous call toOTConnect
fails with theKOTLookErr
result. Timing and the protocol implementation determine whether theOTAccept
function succeeds or fails with thekOTLookErr
result.- The
OTSndUData
function might return thekOTLookErr
result or return successfully, but the endpoint provider issues aT_UDERR
event to indicate that it did not send the datagram.
Error Conditions
Option negotiation might be affected if you try to negotiate an illegal option, a privileged or read-only option, an unsupported option, or an option for an unsupported protocol (level). The results of attempting to negotiate privileged or read-only options are described in "Privileged or Read-Only Options" on page 5-15. This section explains the outcome of negotiating illegal options and describes other problems that might arise during option negotiation.An option is illegal in these cases:
If you specify an illegal option, the following error conditions result depending on the function you used:
- It is the last option in an options buffer, and the length specified in the
TOption.len
field exceeds the remaining size of the options buffer. (The length of the option includes the option header as well as the option value. See Figure 5-2 on page 5-8 for information about the format of option information in an options buffer.)- The option value does not fall within the range of legal values for the option. The range of option values that are valid for a protocol implementation are given in the documentation provided for the protocol.
If the options buffer you pass to a function contains multiple options and one of them is illegal, the function fails as described. However, if you used the
- The
OTOptionManagement
function returns with thekOTBadOptionErr
result.- Either the
OTAccept
orOTConnect
function fails with akOTBadOptionErr
result, or the connection establishment aborts, depending upon the implementation and the time the illegal option is detected. If the connection aborts, the endpoint provider issues aT_DISCONNECT
event. IfOTConnect
is executing synchronously, it fails with thekOTLookErr
result. TheOTAccept
function either succeeds, or fails with thekOTLookErr
result, depending on the implementation.- The
OTSndUData
function fails with thekOTBadOptionErr
result, or it returns successfully, but the endpoint provider issues aT_UDERR
event to indicate that it did not sent the datagram.
OTOptionManagement
function to set options, it is possible that some or all of the legal options in the buffer were successfully negotiated. You can check the current status for the endpoint by calling theOTOptionManagement
function with theT_CURRENT
flag set.The
OTOptionManagement
function fails with thekOTBadOptionErr
result if you specify an unknown value for the option protocol level. Using any other function to specify an unknown option level does not cause the function to fail, but results in the option being ignored.Specifying an option name that is unknown or unsupported by the endpoint does not cause a function to fail. The
OTOptionManagement
function returnsT_NOTSUPPORT
in thestatus
field for the option; the other endpoint functions ignore the unknown options.Obtaining the Maximum Size of an Options Buffer
Different types of endpoints support different numbers of options. For example, an ATP endpoint might support more options than a DDP endpoint and might need a larger buffer to hold the options. When you call theOTOptionManagement
function to change option values, the function returns in theret
parameter a pointer to the buffer containing the negotiated option values. You must have allocated the buffer used to store these options before calling the function. Likewise, when you call theOTListen
,OTRcvUData
,OTRcvURequest
orOTRcvConnect
functions, you can allocate a buffer in which current option values are to be placed when these functions return. In either case, you must specify the size of the buffer, and the buffer must be large enough to hold all of the endpoint's options. Otherwise, the function fails with akOTBufferOverflow
result. You can obtain the maximum size of a buffer used to store options for your endpoint by examining theoptions
field of theTEndpointInfo
structure for the endpoint. You can get a pointer to this structure when you open the endpoint, when you bind the endpoint, or when you call theOTGetEndpointInfo
function.Setting Option Values
You can use theOTOptionManagement
,OTAccept
,OTSndUData
,OTSndURequest
, andOTConnect
functions to set option values. Setting option values results in a negotiation process between you (the client application) and the endpoint provider or, in the case of association-related options, between local and remote clients and their endpoint providers. The section "Initiating an Option Negotiation" on page 5-13 describes the rules that govern an option negotiation that you have initiated using theOTOptionManagement
,OTConnect
,OTSndUData
, orOTSndURequest
functions. The section "Retrieving Values for Connection-Oriented Endpoints," beginning on page 5-21 describes the negotiation rules that hold when you use theOTOptionManagement
orOTAccept
functions to respond to a negotiation. This section describes ways in which you can build the options buffer used to specify the options you want to change.Specifying Option Values
No matter which function you use to set option values, you must allocate a buffer that contains the option value or values you want to change. The options in this buffer are described byTOption
structures; the format of this structure is illustrated in Figure 5-2 on page 5-8. You can concatenate several structures in the buffer, as shown by Figure 5-3 on page 5-8, so long as each structure begins on a long-word boundary. The buffer itself is described by aTNetbuf
structure that specifies the location of the buffer and its size.You can create a buffer that contains the option values you want to set in one of two ways: manually or by using the
OTCreateOptions
function. If you construct the buffer manually, you must do the following:
To have Open Transport create a buffer for you, you must call the
- Allocate the buffer.
- Create a
TOption
structure for each option you want to change.- Initialize each field of the
TOption
structure except for thestatus
field.- Place the
TOption
structures in the buffer, making sure that each begins on a long-word boundary. This enables Open Transport to parse the buffer.- Append a null character to the end of the buffer. This enables Open Transport to tell that it has reached the end of the buffer.
OTCreateOptions
function and pass it a string containing one or more option values. This method saves time and trouble, but you can only use it if all the options in the buffer are for the same level and that level is the same as the top-level protocol for the endpoint provider. That is to say, you could not use this method to construct a buffer that contains DDP-level options for an ATP endpoint. In addition, this method is only guaranteed to work if you are building an options buffer for theOTOptionManagement
function.Listing 5-1 shows how you construct an options buffer manually. The listing creates and initializes two
TOption
structures,ddpOpt
andatpOpt
. It allocates a buffer large enough to contain theTOption
structures and then places those structures in the buffer. Note that the structures are quad-word aligned and that a null character is appended to the end of the buffer.Listing 5-1 Constructing an options buffer manually
TOption *ddpOpt, *atpOpt; unsigned char optionBuffer[41]; ddpOpt = (TOption*)&optionBuffer[0]; ddpOpt->len = 20; ddpOpt->level = ATK_DDP; ddpOpt->name = OPT_CHECKSUM; ddpOpt->status = 0; ddpOpt->value[0] = 1; /* turn checksumming on */ atpOpt = (TOption*)&optionBuffer[20] atpOpt->len = 20; atpOpt->level = ATK_ATP; atpOpt->name = OPT_RELTIMER; atpOpt->status = 0; atpOpt->value[0] = 2; /* purge transaction list every 2 minutes */ optionBuffer[40] = 0;/* add null character to end of buffer */Listing 5-2 shows how you construct an options buffer by using theOTCreateOptions
function. The code initializes a string array,myStr
, to hold option values. It then creates aTOptMgmt
structure, which would later be passed to theOTOptionManagement
function to request the option values specified in the string. Finally, it calls theOTCreateOptions
function to create the options buffer. TheOTCreateOptions
function creates theTOption
structures and places them in the buffer, making sure that the structures are properly aligned.Listing 5-2 Constructing an options buffer using the
OTCreateOptions
function
char* myStr = "BaudRate = 9650 DataBits = 8 Parity = 0 StopBits = 10"; UInt8 buffer[512]; TOptMgmt cmd; cmd.opt.len = 0; cmd.opt.maxlen = sizeof(buffer); cmd.opt.buf = buffer; cmd.flags = T_NEGOTIATE err = OTCreateOptions("SerialA", &myStr, &cmd.opt)In this case, the initial value ofcmd.opt.len
, which is 0, tells theOTCreateOptions
function at what offset it should begin to append option information in the buffer. When the function returns, this field specifies the actual length of the buffer.Setting Default Values
To set all of an endpoint's options to their default values, call theOTOptionManagement
function, specifyingT_NEGOTIATE
for theflags
field and allocating a buffer containing only one option namedT_ALLOPT
. Doing this saves you the trouble of constructing aTOption
structure for every option the endpoint supports. However, there is no guarantee that the provider can honor your request simply because you request default values. Therefore, you must allocate a buffer that is large enough to hold the option values returned in theret
parameter.Allowing the Endpoint Provider to Select an Option Value
You can specify that an endpoint provider selects an appropriate option value by setting the endpoint's value field to the constantT_UNSPEC
. This is especially useful in complex options such as ISO throughput where the option value has an internal structure.Retrieving Option Values
This section describes how you can retrieve information about options, including obtaining current and default option values for an endpoint and obtaining current option values related to a connection, transaction, or datagram.When retrieving option values, you must allocate a buffer that is large enough to contain the options when the function returns. The section "Obtaining the Maximum Size of an Options Buffer" on page 5-17 explains how you do this.
Obtaining Current and Default Values
To obtain some of an endpoint's default or current option values, you call theOTOptionManagement
function. You specifyT_DEFAULT
orT_CURRENT
for theflags
field of thereq
parameter, and you use theoption.buf
field to specify the option names in which you are interested. When the function returns, it placesTOption
structures, describing the default or current option values, in the buffer referenced by theopt.buf
field of theret
parameter.If you are interested in obtaining all of an endpoint's default or current values, you can use the following methods:
Using
- To obtain an endpoint's default values, call the
OTOptionManagement
function, specifyingT_DEFAULT
for the flags field andT_ALLOPT
for the
option name.- To obtain an endpoint's current option values, call the
OTOptionManagement
function, specifyingT_CURRENT
for theflags
field andT_ALLOPT
for the option name.
T_ALLOPT
for the option name allows you to construct an input buffer that contains only one option. Remember, however, that you must allocate an output buffer that is large enough to hold all of an endpoint's option values when the function returns.Retrieving Values for Connection-Oriented Endpoints
When you are establishing a connection, it is possible to negotiate association-
related option values at every point in the connection process, as illustrated in Figure 5-1 on page 5-6. Both the active and passive peers might want to retrieve option values during this process.The passive peer might want to know the proposed option values under negotiation. It can retrieve these by calling the
OTListen
function. After examining the option values returned by theOTListen
function, the passive peer can negotiate option values by specifying the desired option values
with theOTAccept
call used to accept the connection. Using this method,
the passive peer can examine the requested option values before proposing alternate values.The passive peer can also negotiate alternate values by using the
OTOptionManagement
function to preset option values for the endpoint accepting the connection. This sets the current option values for the endpoint so that when the passive peer calls theOTAccept
function, these are the option values that are negotiated with the requested values.The passive peer can try to negotiate option values that are higher than the proposed values. The outcome depends on the protocol. If the protocol rejects the new option values, the connection fails, and the endpoint provider issues a
T_DISCONNECT
event. Depending on timing and the implementation, theOTAccept
function either succeeds or fails with thekOTLookErr
result.The association-related options retrieved by the passive peer are related to the incoming connection, identified by a sequence number, and are not related to the listening endpoint. Option values currently effective for the listening endpoint might affect the values retrieved by the
OTListen
function because the endpoint is involved in the negotiation process, but these values are not the same as the option values related to the connection request. That is to say, calling theOTOptionManagement
function to retrieve the option values that were currently effective for the listening endpoint is likely to yield a different set of values than you would find by examining the values of options passed in thecall
parameter to theOTListen
function.When you establish the connection--that is, when a synchronous call to the
OTConnect
function returns or when the active peer calls theOTRcvConnect
function-- all final negotiated values effective for the connection are returned in the buffer passed in thercvCall
orcall
parameter, respectively. These option values include all association-related options that were received with the connection response and the negotiated values of those non-association-
related options that had been specified on input. Options specified on input to theOTConnect
call that are not supported or that refer to an unknown protocol are ignored and not returned by theOTConnect
orOTRcvConnect
function when it returns.Retrieving Values for Connectionless Transactionless Endpoints
You can retrieve association-related options set for connectionless transactionless endpoints by examining the buffer passed in theudata
parameter to theOTRcvUData
function. These options relate to the incoming datagram, not to the endpoint receiving it. For example, the IEEE 802.2 protocol uses option values to specify whether a datagram is a multicast or broadcast packet.Because the options you retrieve are related to the datagram and not to the listening endpoint, their number and values can change with every transmission.
Because you are receiving information--that is, you are simply reading the contents of the options buffer--you can ignore the
status
field for these options.Retrieving Values for Connectionless Transaction-Based Endpoints
You can retrieve association-related options set for connectionless transaction-
based endpoints by examining the buffer passed in thereq
parameter to theOTRcvURequest
function. These options relate to the current transaction, not to the endpoint receiving the request. Consequently, options and their values can change with each transaction.Because you are receiving information--that is, you are simply reading
the contents of the options buffer--you can ignore thestatus
field for
these options.Parsing an Options Buffer
If you use theOTOptionManagement
function to set, verify, or retrieve values, the function returns in theret
parameter a pointer to a buffer containing option information. You can use theOTCreateOptionString
function to parse this buffer and create a string that lists all options and their current values.The code fragment shown in Listing 5-3 calls the
OTOptionManagement
function to retrieve the option values currently effective for an endpoint. On return, theOTOptionManagement
function stores these in thecmd
structure. Next, the code calls theOTCreateOptionString
function. The first input parameter,"SerialA"
, specifies the name of the protocol. The next input parameter,opts,
is a pointer to the buffer containing the option values returned by theOTOptionManagement
function. The expressioncmd.opt.buf + cmd.opt.len
, which provides the next input parameter, specifies the length of the buffer. Using this information, theOTCreateOptionString
function returns a string containing each option name and its respective value. The final parameter to theOTCreateOptionString
function specifies the length of the string.Listing 5-3 Using the
OTCreateOptionString
function to parse through a buffer
TOptMgmt cmd; UINt8 myBuffer[512]; char myString[256] cmd.opt.len = sizeof(TOption); cmd.opt.maxlen = sizeof(myBuffer); cmd.opt.buf = myBuffer; ((TOption*) buffer)->len = sizeof(TOption); ((TOption*) buffer)->level = COM_SERIAL; ((TOption*) buffer)->name = T_ALLOPT; ((TOption*) buffer)->status = 0; cmd.flags = T_CURRENT; OTOptionManagement(theEndpt, &cmd, &cmd); TOption* opts = (TOption*)cmd.opt.buf; err = OTCreateOptionString("SerialA", &opts, cmd.opt.buf + cmd.opt.len, string, sizeof(string)); printf("Options = \"%s\"", string);
- Note
- The
OTCreateOptionString
function is supplied solely as a debugging aid. You should not include the function in a production version of your application because there is no provision made for localizing string information.![]()
Verifying Option Values
In addition to obtaining default or current values and negotiating new values, you can use theOTOptionManagement
function to verify whether an endpoint supports one or more options. To do this, you construct a buffer containingTOption
structures describing the options you are interested in and pass this buffer in thereq
parameter to theOTOptionManagement
function, specifyingT_CHECK
for the action flag. When the function returns, you can examine thestatus
field of theTOption
structures for the options passed back to you in theret
parameter to determine whether the specified options are supported.